package busterminalweb.servlet;

import busterminal.persistence.BusDAO;
import busterminal.persistence.BusModelDAO;
import busterminal.persistence.DaoFactory;
import busterminal.persistence.RouteDAO;
import busterminal.persistence.ScheduledItemDAO;
import busterminal.persistence.StoppingPointDAO;
import busterminal.persistence.TripDAO;
import busterminal.persistence.jdbc.AbstractJdbcDAO;
import busterminal.persistence.jdbc.JdbcDAOFactory;
import busterminal.services.ServiceLocator;
import busterminalweb.action.Action;
import busterminalweb.action.ActionManager;
import busterminalweb.action.ActionResult;
import busterminalweb.action.DefaultAction;
import busterminalweb.action.bus.*;
import busterminalweb.action.busmodel.*;
import busterminalweb.action.route.CreateRouteAction;
import busterminalweb.action.route.DeleteRouteAction;
import busterminalweb.action.route.EditRouteAction;
import busterminalweb.action.route.FindRouteByStoppingPointNameAction;
import busterminalweb.action.route.RouteAction;
import busterminalweb.action.route.RouteListAction;
import busterminalweb.action.route.SaveRouteAction;
import busterminalweb.action.scheduleditem.CreateScheduledItemAction;
import busterminalweb.action.scheduleditem.DeleteScheduledItemAction;
import busterminalweb.action.scheduleditem.EditScheduledItemAction;
import busterminalweb.action.scheduleditem.FindScheduledItemByRouteNameAction;
import busterminalweb.action.scheduleditem.FindScheduledItemByTimeAction;
import busterminalweb.action.scheduleditem.SaveScheduledItemAction;
import busterminalweb.action.scheduleditem.ScheduledItemListAction;
import busterminalweb.action.stoppingpoint.CreateStoppingPointAction;
import busterminalweb.action.stoppingpoint.DeleteStoppingPointAction;
import busterminalweb.action.stoppingpoint.EditStoppingPointAction;
import busterminalweb.action.stoppingpoint.SaveStoppingPointAction;
import busterminalweb.action.stoppingpoint.StoppingPointListAction;
import busterminalweb.action.trip.CreateTripAction;
import busterminalweb.action.trip.DeleteTripAction;
import busterminalweb.action.trip.EditTripAction;
import busterminalweb.action.trip.SaveTripAction;
import busterminalweb.action.trip.TodayTripListAction;
import busterminalweb.action.trip.TripListAction;
import busterminalweb.action.user.CreateUserAction;
import busterminalweb.action.user.DeleteUserAction;
import busterminalweb.action.user.EditUserAction;
import busterminalweb.action.user.SaveUserAction;
import busterminalweb.action.user.UserListAction;
import busterminalweb.action.user.UserLogin;
import busterminalweb.action.user.UserLogout;
import busterminalweb.authorization.Authorization;
import busterminalweb.authorization.service.Role;
import java.io.IOException;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Сервлет
 */
public class MainServlet extends HttpServlet {

    /**
     * Объект для хранения сервисов
     */
    private ActionManager actionManager;

    /**
     * Инициализация сервлета
     * @throws ServletException если произошла ошибка инициализации
     */
    @Override
    public void init() throws ServletException {
        DaoFactory daoFactory = new JdbcDAOFactory();

        ServiceLocator.registerService(BusDAO.class, daoFactory.getBusDAO());
        ServiceLocator.registerService(BusModelDAO.class, daoFactory.getBusModelDAO());
        ServiceLocator.registerService(RouteDAO.class, daoFactory.getRouteDAO());
        ServiceLocator.registerService(ScheduledItemDAO.class, daoFactory.getScheduledItemDAO());
        ServiceLocator.registerService(StoppingPointDAO.class, daoFactory.getStoppingPointDAO());
        ServiceLocator.registerService(TripDAO.class, daoFactory.getTripDAO());
        ServiceLocator.registerService(Authorization.class, new Authorization());

        actionManager = new ActionManager();

        //Bus
        actionManager.addAction(new CreateBusAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new DeleteBusAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new EditBusAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new SaveBusAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new BusListAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new BusAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER, Role.DISPATCHER);
        actionManager.addAction(new FindBusByStateNumberAction(), Role.values());
        actionManager.addAction(new FindBusByStartYearOfExploitationAction(), Role.values());

        //BusModel
        actionManager.addAction(new CreateBusModelAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new DeleteBusModelAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new EditBusModelAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new SaveBusModelAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new BusModelListAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new BusModelAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER, Role.DISPATCHER);
        actionManager.addAction(new FindBusModelByModelNameAction(), Role.values());

        //Route
        actionManager.addAction(new CreateRouteAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new DeleteRouteAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new EditRouteAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new SaveRouteAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new RouteListAction(), Role.values());
        actionManager.addAction(new RouteAction(), Role.values());
        actionManager.addAction(new FindRouteByStoppingPointNameAction(), Role.values());

        //ScheduledItem
        actionManager.addAction(new CreateScheduledItemAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new DeleteScheduledItemAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new EditScheduledItemAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new FindScheduledItemByRouteNameAction(), Role.values());
        actionManager.addAction(new FindScheduledItemByTimeAction(), Role.values());
        actionManager.addAction(new SaveScheduledItemAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new ScheduledItemListAction(), Role.values());

        //StoppingPoint
        actionManager.addAction(new CreateStoppingPointAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new DeleteStoppingPointAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new EditStoppingPointAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new SaveStoppingPointAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new StoppingPointListAction(), Role.ADMINISTRATOR);

        //Trip
        actionManager.addAction(new CreateTripAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new DeleteTripAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER);
        actionManager.addAction(new EditTripAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER, Role.DISPATCHER);
        actionManager.addAction(new SaveTripAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER, Role.DISPATCHER);
        actionManager.addAction(new TodayTripListAction(), Role.MAIN_DISPATCHER, Role.DISPATCHER);
        actionManager.addAction(new TripListAction(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER, Role.DISPATCHER);

        //Authorization
        actionManager.addAction(new UserLogin(), Role.values());
        actionManager.addAction(new UserLogout(), Role.ADMINISTRATOR, Role.MAIN_DISPATCHER, Role.DISPATCHER);

        //User
        actionManager.addAction(new UserListAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new CreateUserAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new EditUserAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new DeleteUserAction(), Role.ADMINISTRATOR);
        actionManager.addAction(new SaveUserAction(), Role.ADMINISTRATOR);

        actionManager.addAction(new DefaultAction(), Role.values());
    }

    /**
     * Освобождение ресурсов и закрытие соединения с базой данных
     */
    @Override
    public void destroy() {
        super.destroy();

        AbstractJdbcDAO.closeConnection();

        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
            } catch (SQLException e) {
            }
        }
    }

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");

        String actionName = request.getParameter("action");

        if (actionName == null) {
            actionName = "default.action";
        }

        Action action = actionManager.findAction(actionName);
        if (action == null) {
            action = actionManager.findAction("default.action");
        }

        ActionResult forward = action.execute(request, response);

        if (forward.isForward()) {
            RequestDispatcher requestDispatcher = getServletContext().getRequestDispatcher("/WEB-INF/view/" + forward.getViewJsp());
            requestDispatcher.forward(request, response);
        }

        if (forward.isRedirect()) {
            response.sendRedirect(request.getContextPath() + "/MainServlet?action=" + forward.getAction());
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
